#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "cJSON.h"

#define FileName "cfg.json"

struct _cfg {
    char devname[64];
    unsigned int enable;
    unsigned int magic;
    unsigned int version;
    unsigned int crcval;
};

struct _cfg usercfg = {{0}, 0};
cJSON *cfg_js = NULL;


int unserialize_numb_double(cJSON *f, char *item, double *val) {
    int ret = 0; 
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            *val = cJSON_GetNumberValue(s);
            ret = 1;
        }
    }
    return ret;
}

int parse_numb(cJSON *f, char *item, uint32_t *val) {
    int ret = 0; 
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            double number = cJSON_GetNumberValue(s);
            *val = (uint32_t)number;
            ret = 1;
        }else {
            /* 没有的时候填上键值 */
            cJSON_AddNumberToObject(f, item, 0);
        }
    }
    return ret;
}

int parse_str(cJSON *f, char *item, char* val) {
    int ret = 0; 
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            char* src = cJSON_GetStringValue(s);
            if( NULL != strcpy(val, src)) {
                ret = 1;
            }else {
                /* 没有的时候填上键值 */
                cJSON_AddStringToObject(f, item, "");
            }
        }
    }
    return ret;
}

#define myarg(x) printf("%s = %d\r\n", #x, x)
#define GET_NUM32(ITEM, p) parse_numb(root, ITEM, (uint32_t*)p)
#define GET_STR(ITEM, p) parse_str(root, ITEM, (char*)p)

int _parse_text(char *text)
{
    cJSON *root = cJSON_Parse(text);
	if (!root) {
        printf("cJSON unserialize failed\n");
        return -1;
    }else {
        GET_STR("devname", &usercfg.devname);
        GET_NUM32("enable", &usercfg.enable);
        GET_NUM32("magic", &usercfg.magic);
        GET_NUM32("version", &usercfg.version);
        GET_NUM32("crcval", &usercfg.crcval);
	}
    printf("devname is %s\r\n", usercfg.devname);
    myarg(usercfg.enable);
    myarg(usercfg.magic);
    myarg(usercfg.version);
    myarg(usercfg.crcval);
    cJSON_Delete(root);
    return 0;
}

static int _parse_file(const char* file_name)
{
    int ret = 0;
	FILE *f; long len; char *data;
	f = fopen(file_name, "rb");
    if(f == NULL) {
        printf("open faild return\r\n");
        return -1;
    }
	fseek(f, 0, SEEK_END);
	len = ftell(f);
	fseek(f, 0, SEEK_SET);
	data = (char*)malloc(len + 1);
	fread(data, 1, len, f);
	fclose(f);
	if(_parse_text(data)) {
        ret = -1;
    }
	free(data);
    return ret;
}

static int _json_save(cJSON *root)
{ 
    char *out = malloc(10*1024);
    if (!cJSON_PrintPreallocated(root, out, 10*1024, 1)) {
        printf("cJSON Print failed!\n");
        return -1;
    }
    FILE* fp = fopen(FileName ,"w+"); 	
	fprintf(fp, "%s", out);
	fclose(fp);
    free(out);
    return 0;
}

static void _cfg_restore(void)
{       
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "devname", usercfg.devname);
    cJSON_AddNumberToObject(root, "enable", usercfg.enable);
    cJSON_AddNumberToObject(root, "magic", usercfg.magic);
    cJSON_AddNumberToObject(root, "version", usercfg.version);
    cJSON_AddNumberToObject(root, "crcval", usercfg.crcval);
    _json_save(root);
    cfg_js = root;
}

/* __cdecl 所有参数从右到左依次入栈 */
void CJSON_CDECL json_cfg_init(void) { 
    if(_parse_file(FileName)) {
        _cfg_restore();
    }
}

int main(void)
{
    json_cfg_init();
    return 0;
}
